package comm_ctrl

import (
	"fmt"
	"math/rand"
	"net/url"
	"os"
	"path"
	"strings"
	"time"
	"ubt-gin-admin/app/pkg/conf"
	"ubt-gin-admin/app/pkg/enums"
	"ubt-gin-admin/app/pkg/logger"
	"ubt-gin-admin/app/pkg/parse"
	"ubt-gin-admin/app/utils"

	"github.com/gin-gonic/gin"
)

type fileCtrl struct{}

var FileCtrl fileCtrl

// Upload 上传文件
func (c *fileCtrl) Upload(ctx *gin.Context) {
	// 通过头部请求的token获取用户信息
	token := ctx.GetHeader("token")
	userInfo := utils.GetUserInfo(ctx, token)
	if userInfo == nil {
		utils.ToJson(ctx, enums.NoLoginErr.Code, enums.NoLoginErr.Msg, nil)
		return
	}
	//从表单中读取文件
	file, err := ctx.FormFile("upFile")
	if err != nil {
		logger.Error("文件获取失败。" + err.Error())
		utils.ToJson(ctx, enums.ParamErr.Code, enums.ParamErr.Msg, nil)
		return
	}
	var fileName, extName, dateStr, basePath, baseUrl, filePath, srcPath, thumbPath, vstUrl, thumbUrl string
	basePath = conf.Conf.AppConf.RootPath + "/file/"
	baseUrl = conf.Conf.AppConf.BaseUrl + "/file/"
	dateStr = time.Now().Format("200601")
	fileName = file.Filename
	extName = path.Ext(fileName)
	extName = strings.ToLower(extName)
	fileName = fileName[:len(fileName)-len(extName)]
	var maxSize int64 = 200 * 1024 * 1024
	if !strings.Contains(".jpg.png.gif.bmp.jpeg.txt.xls.xlsx.doc.docx.pdf.zip.7z.rar.mp3.wma.mp4.mpeg", extName) {
		utils.ToJson(ctx, enums.UploadNotAllow.Code, enums.UploadNotAllow.Msg, nil)
		return
	}
	if strings.Contains(".jpg.png.gif.bmp.jpeg", extName) {
		maxSize = 5 * 1024 * 1024
		filePath = basePath + "img/src/" + dateStr + "/"
		srcPath = basePath + "img/" + dateStr + "/"
		thumbPath = basePath + "img/thumb/" + dateStr + "/"
		vstUrl = baseUrl + "img/" + dateStr + "/"
		thumbUrl = baseUrl + "img/thumb/" + dateStr + "/"
		// 创建源文件的目录
		if _, err = os.Stat(srcPath); err != nil || os.IsNotExist(err) {
			if err = os.Mkdir(srcPath, os.ModePerm); err != nil {
				logger.Error("上传目录创建失败。" + err.Error())
				utils.ToJson(ctx, enums.UploadPathErr.Code, enums.UploadPathErr.Msg, nil)
				return
			}
		}
		// 创建缩略图的目录
		if _, err = os.Stat(thumbPath); err != nil || os.IsNotExist(err) {
			if err = os.Mkdir(thumbPath, os.ModePerm); err != nil {
				logger.Error("上传目录创建失败。" + err.Error())
				utils.ToJson(ctx, enums.UploadPathErr.Code, enums.UploadPathErr.Msg, nil)
				return
			}
		}
	} else if strings.Contains(".xls.xlsx.doc.docx.pdf", extName) {
		filePath = basePath + "doc/" + dateStr + "/"
		vstUrl = baseUrl + "doc/" + dateStr + "/"
	} else if strings.Contains(".zip.7z.rar", extName) {
		filePath = basePath + "zip/" + dateStr + "/"
		vstUrl = baseUrl + "zip/" + dateStr + "/"
	} else if strings.Contains(".mp3.wma.mp4.mpeg", extName) {
		maxSize = 500 * 1024 * 1024
		filePath = basePath + "media/" + dateStr + "/"
		vstUrl = baseUrl + "media/" + dateStr + "/"
	} else {
		filePath = basePath + "other/" + dateStr + "/"
		vstUrl = baseUrl + "other/" + dateStr + "/"
	}
	if maxSize < file.Size {
		utils.ToJson(ctx, enums.UploadFileSize.Code, enums.UploadFileSize.Msg, nil)
		return
	}
	// 创建目录
	if _, err = os.Stat(filePath); err != nil || os.IsNotExist(err) {
		if err = os.Mkdir(filePath, os.ModePerm); err != nil {
			logger.Error("上传目录创建失败。" + err.Error())
			utils.ToJson(ctx, enums.UploadPathErr.Code, enums.UploadPathErr.Msg, nil)
			return
		}
	}
	//重命名文件
	newName := time.Now().Format("02150405") + fmt.Sprintf("%08v", rand.Intn(100000000)) + extName
	_, err = os.Create(filePath + newName)
	if err != nil {
		logger.Error("文件上传失败。" + err.Error())
		utils.ToJson(ctx, enums.UploadErr.Code, enums.UploadErr.Msg, nil)
		return
	}
	//将文件写到本地
	if err = ctx.SaveUploadedFile(file, filePath+newName); err != nil {
		logger.Error("文件保存失败。" + err.Error())
		utils.ToJson(ctx, enums.UploadErr.Code, enums.UploadErr.Msg, nil)
		return
	}
	// 如果是图片格式的文件，则进行压缩和生成缩略图
	if strings.Contains(".jpg.png.gif.bmp.jpeg", extName) {
		// 压缩图片，高度设为0
		srcPath += newName
		utils.ImgProc.ThumbImage(filePath+newName, srcPath, 1080, 0)
		// 生成缩略图
		thumbPath += newName
		utils.ImgProc.ThumbImage(filePath+newName, thumbPath, 240, 240)
	}
	fileId := utils.NewNanoid(21)
	var fileInfo map[string]string = nil
	fileInfo = make(map[string]string)
	fileInfo["id"] = fileId
	fileInfo["name"] = fileName
	fileInfo["url"] = vstUrl + newName
	fileInfo["thumb"] = thumbUrl + newName
	utils.ToJson(ctx, enums.Succeed.Code, enums.Succeed.Msg, fileInfo)
}

// Download 下载文件
func (c *fileCtrl) Download(ctx *gin.Context) {
	req := &FileUrlReq{}
	// 将请求的参数转换为请求结构体
	if err := parse.Parse(ctx, req); err != "" {
		utils.ToJson(ctx, enums.ParamErr.Code, err, nil)
		return
	}
	// 过滤关键参数值中的非法字符
	req.Url = utils.InputFilter(req.Url, true)

	realPath := "/home/ubt/apps/ubt-gin-admin/" + req.Url[22:]
	strArr := strings.Split(req.Url, "/")
	var fileName string
	if len(strArr) > 1 {
		fileName = strArr[len(strArr)-1]
	}
	if realPath == "" {
		utils.ToJson(ctx, enums.DownloadErr.Code, enums.DownloadErr.Msg, nil)
		return
	}
	if _, err := os.Stat(realPath); err != nil || os.IsNotExist(err) {
		utils.ToJson(ctx, enums.DownloadErr.Code, enums.DownloadErr.Msg, nil)
		return
	}
	fb, err := os.ReadFile(realPath)
	if err != nil {
		utils.ToJson(ctx, enums.DownloadErr.Code, enums.DownloadErr.Msg, nil)
		return
	}
	ctx.Header("content-type", "application/octet-stream")
	ctx.Header("content-disposition", "attachment; filename="+url.QueryEscape(fileName))
	ctx.Header("Access-Control-Expose-Headers", "content-disposition")
	if _, err = ctx.Writer.Write(fb); err != nil {
		utils.ToJson(ctx, enums.DownloadErr.Code, enums.DownloadErr.Msg, nil)
	}
}

// Delete 删除文件
func (c *fileCtrl) Delete(ctx *gin.Context) {
	// 通过头部请求的token获取用户信息
	token := ctx.GetHeader("token")
	userInfo := utils.GetUserInfo(ctx, token)
	if userInfo == nil {
		utils.ToJson(ctx, enums.NoLoginErr.Code, enums.NoLoginErr.Msg, nil)
		return
	}
	req := &FileUrlReq{}
	// 将请求的参数转换为请求结构体
	if err := parse.Parse(ctx, req); err != "" {
		utils.ToJson(ctx, enums.ParamErr.Code, err, nil)
		return
	}
	// 过滤关键参数值中的非法字符
	req.Url = utils.InputFilter(req.Url, true)
	realPath := "/home/ubt/apps/ubt-gin-admin/" + req.Url[22:]
	strArr := strings.Split(req.Url, "/")
	var fileName string
	if len(strArr) > 1 {
		fileName = strArr[len(strArr)-1]
		nameArr := strings.Split(fileName, ".")
		extName := nameArr[len(nameArr)-1]
		var kind int64 = 2
		if strings.Contains(".jpg.png.gif.bmp.jpeg", extName) {
			kind = 1
		}
		utils.ImgProc.RemoveFile(kind, realPath)
		utils.ToJson(ctx, enums.Succeed.Code, enums.Succeed.Msg, nil)
		return
	}
	utils.ToJson(ctx, enums.DeleteFileErr.Code, enums.DeleteFileErr.Msg, nil)
}
